package com.shareyi.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 原始的NIO 服务器
 *
 * @author zhangshibin
 * @since 2018/9/9
 */
public class NicSocketServer {


    public void startServer(NioSingleThreadReader reader, int port) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        serverSocketChannel.configureBlocking(false); //设置为非阻塞模式，成为NIO模式

        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {

            //等待请求，每次等待阻塞3s，超过时间则向下执行，若传入0或不传值，则在接收到请求前一直阻塞
            if (selector.select(3000) == 0) {
                System.out.println("等待请求超时......");
                continue;
            }

            System.out.println("-----处理请求-----");
            //获取待处理的选择键集合
            Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
            while (keyIterator.hasNext()) {
                SelectionKey selectionKey = keyIterator.next();
                try {
                    //如果是连接请求，调用处理器的连接处理方法
                    if(selectionKey.isAcceptable()){
                        this.handleAccept(selectionKey, reader );
                    }
                } catch (IOException e) {
                    keyIterator.remove();
                    continue;
                }
            }
            //处理完毕从待处理集合移除该选择键
            keyIterator.remove();

/*
            SocketChannel socketChannel =
                    serverSocketChannel.accept();

            //在 NIO模式下，未获取到channel也可能返回，需要继续循环
            if (socketChannel == null) {
                continue;
            }
            //将当前渠道的接收&读取数据事件注册到selector
            reader.registerChannel(socketChannel);*/
        }
    }

    /**
     *
     *   连接请求处理方法
     */
    public void handleAccept(SelectionKey selectionKey, NioSingleThreadReader reader) throws IOException {
        //通过选择器键获取服务器套接字通道，通过accept()方法获取套接字通道连接
        SocketChannel socketChannel = ((ServerSocketChannel)selectionKey.channel()).accept();
        //设置套接字通道为非阻塞模式
        socketChannel.configureBlocking(false);
        //为套接字通道注册选择器，该选择器为服务器套接字通道的选择器，即选择到该SocketChannel的选择器
        //设置选择器关心请求为读操作，设置数据读取的缓冲器容量为处理器初始化时候的缓冲器容量
        reader.registerChannel(socketChannel);
        //socketChannel.register(selectionKey.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
    }
}
